package han.chensing.latos.maker.windows.widget.simulator;

/**
 * My math is bad
 * So I would rather not modify this class
 */
public class SimulatorMath {

    private float width;
    private float height;

    public float getWidth() {
        return width;
    }

    public void setWidth(float width) {
        this.width = width;
    }

    public float getHeight() {
        return height;
    }

    public void setHeight(float height) {
        this.height = height;
    }

    public SimulatorMath(float width, float height) {
        this.width = width;
        this.height = height;
    }

    public float[] getCrossPointWithScreen(float x, float y, float degree){
        degree=fixDegree(degree);
        int gx=getGx(degree);
        double rad=Math.toRadians(degree);
        double sin=Math.sin(rad);
        double cos=Math.cos(rad);
        double ncTan = switch (gx) {
            case 1, 3 -> sin / cos;
            case 2, 4 -> cos / sin;
            default -> 0;
        };
        double[] out=new double[2];
        switch (gx) {
            case 1 -> {
                out[0] = width;
                out[1] = y + (width - x) * ncTan;
            }
            case 2 -> {
                out[1] = height;
                out[0] = x + ncTan * (height - y);
            }
            case 3 -> {
                out[0] = 0;
                out[1] = y - x * ncTan;
            }
            case 4 -> {
                out[0] = x - y * ncTan;
                out[1] = 0;
            }
        }
        return new float[]{(float) out[0],(float) out[1]};
    }

    public int getGx(float degree){
        degree=fixDegree(degree);
        if((degree>=315&&degree<=360)||(degree>=0&&degree<45)) return 1;
        else if(degree>=45&&degree<135)return 2;
        else if(degree>=135&&degree<225)return 3;
        else if(degree>=225&&degree<315)return 4;
        else return -1;
    }

    public float fixDegree(float degree){
        float remain=degree%360f;
        return remain<0?360+remain:remain;
    }

    public float[] getPointInAwayFromALine(float x, float y, float degree, float distance){
        degree=fixDegree(degree);
        double rad=Math.toRadians(degree);
        double cos=Math.cos(rad);
        double sin=Math.sin(rad);
        double da=cos*distance;
        double db=sin*distance;
        return new float[]{x+(float)da,y+(float)db};
    }

    public float[] getProjectionPointInLine(
            float lx,float ly,float degree,
            float px,float py){
        degree=fixDegree(degree);
        int gx=getGx(degree);
        float[] pos=new float[2];
        double rad=Math.toRadians(degree);
        double sin=Math.sin(rad);
        double cos=Math.cos(rad);
        switch (gx) {
            case 1, 3 -> {
                double tan = sin / cos;
                double tmp = py - ly - (px - lx) * tan;
                pos[0] = (float) (px + tmp * cos * sin);
                pos[1] = (float) (py - tmp * cos * cos);
            }
            case 2, 4 -> {
                double cot = cos / sin;
                double tmp = px - lx - (py - ly) * cot;
                pos[0] = (float) (px - tmp * sin * sin);
                pos[1] = (float) (py + tmp * sin * cos);
            }
        }
        return pos;
    }

    public boolean isPointInJudgeRange(
            float lx,float ly,float degree,
            float px,float py,float width){
        degree=fixDegree(degree);
        int gx=getGx(degree);
        double rad=Math.toRadians(degree);
        double sin,cos,cotOrTan;
        sin=Math.sin(rad);
        cos=Math.cos(rad);
        double p1=0,p2=0,ld1,ld2,d;
        switch (gx) {
            case 1, 3 -> {
                cotOrTan = sin / cos;
                ld1 = width / cos;
                d = py - ly;
                ld2 = d * cotOrTan;
                p1 = lx - (ld2 + ld1);
                p2 = lx - (ld2 - ld1);
            }
            case 2, 4 -> {
                cotOrTan = cos / sin;
                ld1 = width / sin;
                d = py - ly;
                ld2 = d * cotOrTan;
                p1 = ly + (ld2 + ld1);
                p2 = ly + (ld2 - ld1);
            }
        }
        return switch (gx) {
            case 1 -> (px >= p1 && px <= p2);
            case 3 -> (px >= p2 && px <= p1);
            case 2 -> (py >= p2 && py <= p1);
            case 4 -> (py >= p1 && py <= p2);
            default -> false;
        };
    }

    public float distance(float x1,float y1,float x2,float y2){
        return (float)(Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2)));
    }

    public float distance(float[] p1,float[] p2){
        return distance(p1[0],p1[1],p2[0],p2[1]);
    }
}
